use std::fmt::Debug;
use std::ops::{Add, AddAssign, Mul};
use anyhow::{Result, anyhow};

#[derive(Debug)]
pub struct Matrix<T: Debug> {
    data: Vec<T>,
    row: usize,
    col: usize,
}


pub fn multiply<T>(a: &Matrix<T>, b: &Matrix<T>) -> Result<(Matrix<T>)>
    where
        T: Debug + Copy + Add<Output=T> + Mul<Output=T> + AddAssign,
{
    if a.col != b.row {
        return Err(anyhow!("Matrix multipy error: a.col != b.row"));
    }
    let mut data = Vec::with_capacity(a.col * b.row);

    for i in 0..a.col {
        for j in 0..b.row {
            for k in 0..a.row {
                data[i * b.col + j] += a.data[i * a.col + k] * b.data[k * b.col + j];
            }
        }
    }
    Ok(Matrix {
        data,
        col: a.row,
        row: b.col,
    })
}


impl<T: Debug> Matrix<T> {
    pub fn new(data: impl Into<Vec<T>>, row: usize, col: usize) -> Self {
        Self {
            data: data.into(),
            row,
            col,
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_matrix_multiply() -> Result<()> {
        Ok(())
    }
}
